package com.lincoln.framework.bean;

import com.lincoln.framework.exception.ErrorFormatException;
import com.lincoln.framework.interfaces.BaseDecoder;
import com.lincoln.framework.interfaces.BaseDeviceInfo;
import com.lincoln.framework.interfaces.BaseProtocol;
import com.lincoln.util.ResizingArrayStack;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.util.List;

/**
 * 处理带消息号的消息解码器
 *
 * @author lincoln
 */
@Slf4j
public class AbstractDecoder extends BaseDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
        // 可读长度必须大于基本长度a
        if (buffer.readableBytes() >= 1) {
            BaseDeviceInfo deviceInfo = ProtocolContext.getDevice();

            byte b = buffer.readByte();
            if (deviceInfo.getHeaderCache().size() >= AbstractProtocol.HEAD_DATA.length) {
                deviceInfo.getHeaderCache().pop();
            }
            deviceInfo.getHeaderCache().push(b);

            // 如果过去一段byte流与帧首相同,则重新开始读取
            boolean isHead = false;
            if (deviceInfo.getHeaderCache().size() == AbstractProtocol.HEAD_DATA.length) {
                isHead = true;
                Object[] a = deviceInfo.getHeaderCache().data();
                for (int i = 0; i < AbstractProtocol.HEAD_DATA.length; i++) {
                    if (((Byte) a[i]).byteValue() != AbstractProtocol.HEAD_DATA[i]) {
                        isHead = false;
                        break;
                    }
                }
            }

            //读取到了帧首
            if (isHead) {
                deviceInfo.setTailCache(new ResizingArrayStack<>());
                deviceInfo.setCache(new ResizingArrayStack<>());
                // 将帧首赋值给cache
                for (int i = 0;i<AbstractProtocol.HEAD_DATA.length - 1;i++) {
                    deviceInfo.getCache().push(AbstractProtocol.HEAD_DATA[i]);
                }
                deviceInfo.setRecord(true);
            }

            if (deviceInfo.isRecord()) {
                if (deviceInfo.getTailCache().size() >= AbstractProtocol.TAIL_DATA.length) {
                    deviceInfo.getTailCache().pop();
                }
                deviceInfo.getTailCache().push(b);
                deviceInfo.getCache().push(b);

                // 如果过去一段byte流与帧首相同,则重新开始读取
                boolean isTail = false;
                if (deviceInfo.getTailCache().size() == AbstractProtocol.TAIL_DATA.length) {
                    isTail = true;
                    Object[] a = deviceInfo.getTailCache().data();
                    for (int i = 0; i < AbstractProtocol.TAIL_DATA.length; i++) {
                        if (((Byte) a[i]).byteValue() != AbstractProtocol.TAIL_DATA[i]) {
                            isTail = false;
                            break;
                        }
                    }
                }

                //读取到了帧首
                if (isTail) {
                    Object[] bs = deviceInfo.getCache().data();
                    byte[] data = new byte[bs.length];
                    for (int i = 0; i < bs.length; i++) {
                        data[i] = ((Byte) bs[i]).byteValue();
                    }

                    deviceInfo.setHeaderCache(new ResizingArrayStack<>());
                    deviceInfo.setTailCache(new ResizingArrayStack<>());
                    deviceInfo.setCache(new ResizingArrayStack<>());
                    deviceInfo.setRecord(false);
                    // 打印日志
                    StringBuilder content = new StringBuilder();
                    for (byte bb : data) {
                        content.append(Integer.toHexString(bb));
                        content.append(",");
                    }
                    String str = content.toString();
                    str = str.substring(0, str.length() - 1);
                    if(str.length() > 1000){}
                    log.info("收到来自" + ProtocolContext.getDevice().getPrimaryKey() + "帧:" + (str.length() > 1000?str.substring(0,1000) + "...":str));

                    // 读取data数据
                    try {
                        BaseProtocol protocol = new AbstractProtocol(data);
                        out.add(protocol);
                    } catch (NegativeArraySizeException e) {
                        log.error("错误:收到的帧长度为负数");
                    } catch (ErrorFormatException e) {
                        log.error(e.getMessage());
                    }
                }
            }
        }
    }

    /**
     * 将gbk转utf8
     *
     * @param gbkStr
     * @return
     */
    public static String gbk2utf8(String gbkStr) {
        try {
            return new String(gbk2utf8Bytes(gbkStr), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            return gbkStr;
        }
    }

    /**
     * 将gbk字符串转成utf8字节集
     *
     * @param gbkStr
     * @return
     */
    public static byte[] gbk2utf8Bytes(String gbkStr) {
        int n = gbkStr.length();
        byte[] utfBytes = new byte[3 * n];
        int k = 0;
        for (int i = 0; i < n; i++) {
            int m = gbkStr.charAt(i);
            if (m < 128 && m >= 0) {
                utfBytes[k++] = (byte) m;
                continue;
            }
            utfBytes[k++] = (byte) (0xe0 | (m >> 12));
            utfBytes[k++] = (byte) (0x80 | ((m >> 6) & 0x3f));
            utfBytes[k++] = (byte) (0x80 | (m & 0x3f));
        }
        if (k < utfBytes.length) {
            byte[] tmp = new byte[k];
            System.arraycopy(utfBytes, 0, tmp, 0, k);
            return tmp;
        }
        return utfBytes;
    }
}
